﻿using System.Collections.Generic;
using System.Linq;
using Medianamik.Core;
using Medianamik.Service.ActiveDirectory.Configuration;
using Medianamik.Service.ActiveDirectory.Repository;
using Medianamik.Service.ActiveDirectory.Type;
using StructureMap;
using Medianamik.Core.Logging;

namespace Medianamik.Service.ActiveDirectory.Service
{
    public class MembershipService : IMembershipService
    {
        private readonly IDomainService _domainService;
        private readonly IMembershipRepository _membershipRepo;
        private readonly IGroupAssociationsRepository _groupAssociationRepo;

        private IEnumerable<IMedianamikActiveDirectoryAssociationGroup> _groups;
        private IEnumerable<IMedianamikActiveDirectoryAssociationGroup> Groups
        {
            get {
                    if (_groups == null)
                        _groups = _groupAssociationRepo.All();
                    
                    return _groups;
                }
        }

        public MembershipService()
        {
            _membershipRepo = new Container(new Registratrion.RepositoryRegistry()).GetInstance<IMembershipRepository>();  //ObjectFactory.GetInstance<IMembershipRepository>();
            _groupAssociationRepo = new Container(new Registratrion.RepositoryRegistry()).GetInstance<IGroupAssociationsRepository>();  //ObjectFactory.GetInstance<IGroupAssociationsRepository>();
            _domainService = new Container(new Registratrion.ServiceRegistry()).GetInstance<IDomainService>(); //ObjectFactory.GetInstance<IDomainService>();
        }

        private ILogger _logger;
        private ILogger Logger
        {
            get
            {
                return _logger
                    ?? (_logger = new ObjectFactory<ILogger>().Get("ActionManagerLogger"));
            }
        }

        public bool UserCanLogin(string userName)
        {
            Logger.Trace("BEGIN UserCanLogin");
            Logger.Trace("Username: " + userName);
            var domainUser = _domainService.GetUser(userName);

            if (domainUser == null)
            {
                Logger.Trace("END UserCanLogin - RETURN FALSE");
                return false;
            }

            Logger.Trace("END UserCanLogin - IsDomainUserGroupsMatchWithMedianamikGroups");
            return IsDomainUserGroupsMatchWithMedianamikGroups(domainUser.Groups);
        }

        public void SetupUserPermissions(string userName)
        {       
            var domainUser = _domainService.GetUser(userName);

            _membershipRepo.LoadAndCreateUserWithDomainUser(domainUser);
            _membershipRepo.SetUserPermissions(userName, GetMathchingGroups(domainUser.Groups));
        }

        private string[] GetMathchingGroups(IEnumerable<string> usersGroups)
        {
            return
                usersGroups.SelectMany(
                    userGroup =>
                    Groups.Where(group => group.ActiveDirectoryGroup.Equals(userGroup)).Select(
                        group => group.MedianamikGroup)).ToArray();

        }

        private bool IsDomainUserGroupsMatchWithMedianamikGroups(IEnumerable<string> userGroups)
        {
            Logger.Trace("BEGIN IsDomainUserGroupsMatchWithMedianamikGroups");

            if (userGroups == null)
            {
                Logger.Trace("END IsDomainUserGroupsMatchWithMedianamikGroups - RETURN FALSE");
                return false;
            }

            Logger.Trace("UserGroups LIST BEGIN");
            userGroups.ForEach(p => Logger.Trace(p));
            Logger.Trace("UserGroups LIST END");

            var mdkGroups = Groups.Select(g => g.ActiveDirectoryGroup);

            Logger.Trace("MedianamikGroups LIST BEGIN");
            mdkGroups.ForEach(p => Logger.Trace(p));
            Logger.Trace("MedianamikGroups LIST END");

            Logger.Trace("END IsDomainUserGroupsMatchWithMedianamikGroups - RETURN " + mdkGroups.Any(mdkGroup => userGroups.Any(userGroup => userGroup.EqualsIgnoreCase(mdkGroup))));
            return mdkGroups.Any(mdkGroup => userGroups.Any(userGroup => userGroup.EqualsIgnoreCase(mdkGroup)));
        }
    }

    public interface IMembershipService
    {
        bool UserCanLogin(string userName);
        void SetupUserPermissions(string userName);
    }
}